﻿// -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	SmartLib
//  File name:	SqlMultiBulkInsert.cs
//  Developer:	Igor Solomatov
//  Created:	15.03.2013
// 
// -------------------- iSharePoint -------------------- //

using System;
using System.Collections.Generic;
using System.Threading;

namespace Smart.SQL
{
	public class SqlMultiBulkInsert
	{
		public SqlSettings Settings { get; set; }
		public int BatchSize { get; set; }

		public Dictionary<string, SqlBulkInsert> Tables { get; set; }

		protected ReaderWriterLockSlim SyncObj = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);

		public SqlMultiBulkInsert(SqlSettings settings, int batchSize)
		{
			Settings = settings;
			BatchSize = batchSize;
			Tables = new Dictionary<string, SqlBulkInsert>(StringComparer.OrdinalIgnoreCase);
		}

		/// <summary>
		/// Initilize table for bulk insert
		/// </summary>
		public void InitTable(string tableName, Action<SqlBulkInsert> initTable)
		{
			using (new WriteLock(SyncObj))
			{
				var bulkInsert = Tables.SafeGet(tableName);

				if (bulkInsert != null) return;

				if (initTable == null)
					throw new ArgumentNullException("initTable");

				Tables[tableName] = bulkInsert = new SqlBulkInsert(Settings, tableName, BatchSize);

				initTable(bulkInsert);
			}
		}

		/// <summary>
		/// Returns table by <paramref name="tableName"/>
		/// </summary>
		public SqlBulkInsert GetTable(string tableName)
		{
			using (new ReadLock(SyncObj))
			{
				if (String.IsNullOrEmpty(tableName))
					throw new ArgumentNullException("tableName");

				var bulkInsert = Tables.SafeGet(tableName);

				if (bulkInsert == null)
					throw new InvalidOperationException("table " + tableName + " is not inited!");

				return bulkInsert;
			}
		}

		/// <summary>
		/// Returns unique value in <paramref name="tableName"/> by <paramref name="key"/>
		/// </summary>
		public int GetUnique(string tableName, object key)
		{
			using (new ReadLock(SyncObj))
			{
				var bulkInsert = GetTable(tableName);

				if (!bulkInsert.UniqueValueCaseSensitive && (key is string))
					key = ((string)key).ToLower();

				return
					bulkInsert.UniqueValues != null
						? bulkInsert.UniqueValues.SafeGet(key, -1)
						: -2;
			}
		}

		/// <summary>
		/// Sets unique <paramref name="value"/> in <paramref name="tableName"/> by <paramref name="key"/>
		/// </summary>
		public void SetUnique(string tableName, object key, int value)
		{
			using (new ReadLock(SyncObj))
			{
				var bulkInsert = GetTable(tableName);

				bulkInsert.SetUnique(key, value);
			}
		}

		/// <summary>
		/// Returns identity value by unique <paramref name="value"/> in <paramref name="tableName"/>
		/// </summary>
		public int GetIdentityByUnique(string tableName, object value)
		{
			using (new ReadLock(SyncObj))
			{
				var bulkInsert = GetTable(tableName);

				return
					bulkInsert.GetIdentityByUnique(value);
			}
		}

		/// <summary>
		/// Insert row
		/// </summary>
		/// <returns>-1 if failed, 0 if succeeded, > 0 if succeeded and identity used</returns>
		public int Insert(string tableName, Dictionary<string, object> row)
		{
			using (new ReadLock(SyncObj))
			{
				var bulkInsert = GetTable(tableName);

				return
					bulkInsert.Insert(row);
			}
		}

		/// <summary>
		/// Insert row
		/// </summary>
		/// <returns>-1 if failed, 0 if succeeded, > 0 if succeeded and identity used</returns>
		public int InsertUnique(string tableName, Dictionary<string, object> row)
		{
			using (new ReadLock(SyncObj))
			{
				var bulkInsert = GetTable(tableName);

				return
					bulkInsert.InsertUnique(row);
			}
		}

		public bool Purge()
		{
			using (new WriteLock(SyncObj))
			{
				foreach (var pair in Tables)
				{
					if (!pair.Value.Purge())
						return false;
				}

				return true;
			}
		}
	}
}